/* ========================================================================= */
/* ------------------------------------------------------------------------- */
/*!
  \file			mainwindow.cc
  \date			Sep 2011
  \author		TNick

  \brief		Contains the implementation for MainWindow class


  Copyright (c) 2011, Nicu Tofan
 All rights reserved.

 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in the
      documentation and/or other materials provided with the distribution.
    * Neither the name of the copyright holder nor the
      names of its contributors may be used to endorse or promote products
      derived from this software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL NICU TOFAN BE LIABLE FOR ANY
 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

*/
/* ------------------------------------------------------------------------- */
/* ========================================================================= */
//
//
//
//
/*  INCLUDES    ------------------------------------------------------------ */

#include    <main.h>

#include	<QSettings>
#include	<QFile>
#include	<QStringList>
#include	<QTextStream>
#include	<QFileDialog>
#include	<QMessageBox>
#include	<QDateTime>

#include	"mainwindow.h"
#include	"ui_mainwindow.h"

/*  INCLUDES    ============================================================ */
//
//
//
//
/*  CLASS    --------------------------------------------------------------- */

/* ------------------------------------------------------------------------- */
MainWindow::MainWindow	(QWidget *parent) :
	QMainWindow(parent),
	ui(new Ui::MainWindow)
{
	ui->setupUi(this);

	/* load help */
	QFile new_f(":res/html/RegExp.html");
	if (new_f.open(QFile::ReadOnly))
		{
			QTextStream in(&new_f);
			ui->tx_Help->setHtml(in.readAll());
			new_f.close();
		}

	QObject::connect(
				ui->tx_Input,
				SIGNAL(textChanged()),
				this,
				SLOT(testConditionsChanged()));
	QObject::connect(
				ui->tx_RegEx,
				SIGNAL(textChanged()),
				this,
				SLOT(testConditionsChanged()));


	/* panel position and size */
	QSettings settings;
	settings.beginGroup("target_window_pos");
	int need_parse = 0;
	QString tmp_s;
	QPoint pos = settings.value("pos", QPoint(420, 50)).toPoint();
	QSize size = settings.value("size", QSize(width(), height())).toSize();
	move(pos);
	resize(size);
	ui->splitter_2->restoreState(settings.value("spl_222").toByteArray());
	ui->splitter->restoreState(settings.value("spl_111").toByteArray());
	tmp_s = settings.value("ck_text", QString()).toString();
	if (!tmp_s.isEmpty())
		{
			ui->tx_Input->setPlainText(tmp_s);
			need_parse++;
		}
	ui->tab_Right->setCurrentIndex(
				settings.value("right_index", 0).toInt());
	ui->tx_Folder->setText(settings.value("input_folder").toString());
	tmp_s = settings.value("reg_exp").toString();
	if (!tmp_s.isEmpty())
		{
			ui->tx_RegEx->setPlainText(tmp_s);
			need_parse++;
		}
	ui->tx_ReplaceText->setPlainText(settings.value("replacer").toString());
	ui->tx_FileTypes->setText(settings.value("file_pattern").toString());



	settings.endGroup();

	/* menu with file types */
	QMenu * m_BtnAddFT = new QMenu(this);
	m_BtnAddFT->addAction(
				QString("All files (clear)"))
			->setToolTip(QString(" "));
	m_BtnAddFT->addAction(
				QString("C/C++ files (*.c *.cc *.cpp *.h *.hpp)"))
			->setToolTip(QString("*.c *.cc *.cpp *.h *.hpp"));
	m_BtnAddFT->addAction(
				QString("Python files (*.py)"))
			->setToolTip(QString("*.py"));

	connect(
				m_BtnAddFT,
				SIGNAL(triggered(QAction*)),
				this,
				SLOT(addFileterFileType(QAction*)));
	ui->b_AddFlTypes->setMenu(m_BtnAddFT);

	if (need_parse == 2)
		{
			testConditionsChanged();
		}


}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
MainWindow::~MainWindow	(void)
{

	delete ui;
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void    MainWindow::doFilesInFolder         (
	QDir crt_dir, QStringList sl_files)
{

	/* the index of the file in index */
	int idx_in_fld = 0;


	if (!sl_files.isEmpty())
		{
			crt_dir.setNameFilters(sl_files);
		}
	crt_dir.setFilter(QDir::Files | QDir::Hidden | QDir::NoSymLinks);
	crt_dir.setSorting(QDir::NoSort);
	QRegExp regex(
				getTextPattern(),
				Qt::CaseInsensitive,
				QRegExp::RegExp2 );
	regex.setMinimal(true);

	QString s_to_place = ui->tx_ReplaceText->toPlainText();

	QFileInfoList list = crt_dir.entryInfoList();
	for (int i = 0; i < list.size(); ++i) {
		QFileInfo fileInfo = list.at(i);
		ui->statusbar->showMessage(fileInfo.fileName());
		if (fileInfo.size() < RER_MAX_FILE_SIZE)
			{
				QFile   file_hdl(fileInfo.absoluteFilePath());
				if (file_hdl.open(QFile::ReadOnly))
					{
						QTextStream txs(&file_hdl);
						QString fl_cont = txs.readAll();
						file_hdl.close();
						QString fl_out;
						int res = 0;
						int prev_idx = 0;
						QString s_before_loop = s_to_place;
						if (!s_before_loop.isEmpty())
							{
								s_before_loop = s_before_loop
										.replace(QString("/{FullFile}\\"), fileInfo.absoluteFilePath(), Qt::CaseInsensitive)
										.replace(QString("/{Path}\\"), fileInfo.path(), Qt::CaseInsensitive)
										.replace(QString("/{FileNameExt}\\"), fileInfo.fileName(), Qt::CaseInsensitive)
										.replace(QString("/{FileName}\\"), fileInfo.baseName(), Qt::CaseInsensitive)
										.replace(QString("/{Date}\\"), fileInfo.created().toString("dd.MM.yyyy"), Qt::CaseInsensitive)
										.replace(QString("/{TimeHMS}\\"), fileInfo.created().toString("hh:mm:ss"), Qt::CaseInsensitive)
										.replace(QString("/{TimeHM}\\"), fileInfo.created().toString("hh:mm"), Qt::CaseInsensitive)
										.replace(QString("/{Ext}\\"), fileInfo.suffix(), Qt::CaseInsensitive)
										.replace(QString("/{FileNameU}\\"), fileInfo.baseName().toUpper(), Qt::CaseInsensitive)
										.replace(QString("/{FileNameL}\\"), fileInfo.baseName().toLower(), Qt::CaseInsensitive)
										.replace(QString("/{FileSizeB}\\"), QString("%1").arg(fileInfo.size()), Qt::CaseInsensitive)
										.replace(QString("/{FileIdx}\\"), QString("%1").arg(iter_file_index), Qt::CaseInsensitive)
										.replace(QString("/{InFldIdx}\\"), QString("%1").arg(idx_in_fld), Qt::CaseInsensitive);
							}

						res = regex.indexIn(fl_cont, res);
						int idxInFile = 0;
						while (res != -1)
							{
								int fnd_len = regex.cap(0).length();
								if (res - prev_idx > 0)
									fl_out += fl_cont.mid(
												prev_idx,
												res - prev_idx);
								QString s_in_loop = s_before_loop;
								if (!s_in_loop.isEmpty())
									{
										s_in_loop = s_in_loop
												.replace(QString("/{InFileIdx}\\"), QString("%1").arg(idxInFile), Qt::CaseInsensitive)
												.replace(QString("/{InFileIdx1}\\"), QString("%1").arg(idxInFile+1), Qt::CaseInsensitive)
												.replace(QString("/{GlobalIdx}\\"), QString("%1").arg(iter_repl_index), Qt::CaseInsensitive);
									}
								fl_out += s_in_loop;
								prev_idx = res + fnd_len;
								res = regex.indexIn(fl_cont, res+fnd_len);
								idxInFile++;
								iter_repl_index++;
							}
						if (prev_idx < fl_cont.length())
							{
								fl_out += fl_cont.mid(
											prev_idx,
											fl_cont.length() - prev_idx);
							}
						iter_file_index++;
						idx_in_fld++;

						QString s_out_file =
								fileInfo.absoluteFilePath() +
								QString(".REPLACER.tmp");
						QFile file_out(s_out_file);
						if (file_out.open(QFile::WriteOnly))
							{
								QTextStream txs2(&file_out);
								txs2 << fl_out;
								txs2.flush();
								file_out.close();
								QFile::remove(fileInfo.absoluteFilePath());
								file_out.copy(fileInfo.absoluteFilePath());
							}
						file_out.remove();
					}
			}
	}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void    MainWindow::doScanFolder         (
	QString s_crt_folder, QStringList sl_files)
{
	QDir crt_dir(s_crt_folder);

	/* relief the pressure off the stack */
	doFilesInFolder(crt_dir, sl_files);

	ui->statusbar->showMessage(s_crt_folder);

	crt_dir.setFilter(
				QDir::Dirs | QDir::Hidden |
				QDir::NoDotAndDotDot | QDir::NoSymLinks);
	crt_dir.setSorting(QDir::NoSort);
	foreach(QString diritr, crt_dir.entryList())
		{
			doScanFolder(crt_dir.path() + QChar('/') + diritr, sl_files);
		}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void MainWindow::on_b_GO_clicked()
{
	QString s_init_folder = ui->tx_Folder->text();
	if (s_init_folder.isEmpty())
		{
			QMessageBox::critical(
						this,
						QObject::tr("Folder error!!!"),
						QObject::tr("No path was specified.")
						);
			return;
		}

	QDir crt_dir(s_init_folder);
	if (!crt_dir.exists())
		{
			QMessageBox::critical(
						this,
						QObject::tr("Folder error!!!"),
						QObject::tr("The folder %1 does not exists.")
						.arg(s_init_folder)
						);
			return;
		}
	QStringList sl_files = ui->tx_FileTypes->text().split(
				QChar(' '), QString::SkipEmptyParts);

	enableContent(false);
	iter_file_index = 0;
	iter_repl_index = 0;
	doScanFolder(s_init_folder, sl_files);
	enableContent(true);
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void MainWindow::on_b_Close_clicked()
{
	close();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void MainWindow::on_b_Folder_clicked()
{
	QString fileName = QFileDialog::getExistingDirectory(
				qApp->activeWindow(),
				tr("Select location to scan"),
				ui->tx_Folder->text()
				);
	if (!fileName.isEmpty())
		{
			ui->tx_Folder->setText(fileName);
		}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
QString			MainWindow::getTextPattern      			(void)
{
	QString out_s = ui->tx_RegEx->toPlainText()
			.replace(QChar('\r'), QChar('\n'))
			.replace(QChar(9), QChar(' '));

	QStringList to_ck = out_s.split(QChar('\n'),QString::SkipEmptyParts);
	if (to_ck.count() == 0)
		{
			return QString();
		}
	out_s.clear();

	for (int i = 0; i < to_ck.count(); i++)
		{
			QStringList ln_cont = to_ck.at(i).split(
						QChar(' '),QString::SkipEmptyParts);
			if (ln_cont.count() > 0)
				{
					if (i > 0)
						out_s += QString("\\s*");
					for (int j = 0; j < ln_cont.count(); j++)
						{
							out_s += ln_cont.at(j);
							if (j < ln_cont.count() - 1)
								out_s += QString("\\s+");
							else
								out_s += QString("\\s*");
						}
					if (i < to_ck.count()-1)
						out_s += QString("[\\n|\\r]+");
				}
		}

	return out_s;
}
/* ========================================================================= */


/* ------------------------------------------------------------------------- */
void			MainWindow::testConditionsChanged			(void)
{
	QString to_ck = ui->tx_Input->toPlainText();
	if (to_ck.isEmpty())
		{
			ui->tx_Output->setPlainText(QString());
			return;
		}
	QString ck = getTextPattern();
	if (ck.isEmpty())
		{
			ui->tx_Output->setPlainText(QString());
			return;
		}


	QRegExp regex(
				ck,
				Qt::CaseInsensitive,
				QRegExp::RegExp2 );
	regex.setMinimal(true);
	int res = regex.indexIn(to_ck);
	if (res != -1)
		{
			ui->tx_Output->setPlainText(regex.cap(0));
		}
	else
		{
			ui->tx_Output->setPlainText(QString());
		}

}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void        MainWindow::closeEvent              (QCloseEvent *event)
{
	QSettings settings;

	settings.beginGroup("target_window_pos");
	settings.setValue("pos", pos());
	settings.setValue("size", size());
	settings.setValue("spl_222", ui->splitter_2->saveState());
	settings.setValue("spl_111", ui->splitter->saveState());
	settings.setValue("ck_text", ui->tx_Input->toPlainText());
	settings.setValue("right_index", ui->tab_Right->currentIndex());
	settings.setValue("input_folder", ui->tx_Folder->text());
	settings.setValue("reg_exp", ui->tx_RegEx->toPlainText());
	settings.setValue("replacer", ui->tx_ReplaceText->toPlainText());
	settings.setValue("file_pattern", ui->tx_FileTypes->text());

	settings.endGroup();


	event->accept ();
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void        MainWindow::addFileterFileType      (QAction* p_act)
{

	if (p_act->toolTip().count() < 2)
		{
			ui->tx_FileTypes->clear();
		}
	else
		{
			QStringList sl_exist = ui->tx_FileTypes->text().split(
						QChar(' '),
						QString::SkipEmptyParts);
			QStringList sl_add = p_act->toolTip().split(
						QChar(' '),
						QString::SkipEmptyParts);
			foreach (QString s_itr, sl_add)
				{
					if (!sl_exist.contains(s_itr,Qt::CaseInsensitive))
						{
							sl_exist.append(s_itr);
						}
				}
			ui->tx_FileTypes->setText(
						sl_exist.join(QString(' ')));
		}
}
/* ========================================================================= */

/* ------------------------------------------------------------------------- */
void        MainWindow::enableContent       (bool b_en)
{
	ui->tx_Folder->setEnabled(b_en);
	ui->b_Folder->setEnabled(b_en);
	ui->tx_RegEx->setEnabled(b_en);
	ui->tx_FileTypes->setEnabled(b_en);
	ui->tx_Input->setEnabled(b_en);
	ui->tx_Output->setEnabled(b_en);
	ui->tx_ReplaceText->setEnabled(b_en);
	ui->b_Close->setEnabled(b_en);
	ui->statusbar->showMessage(
				(b_en ? QString("Completed") : QString("Starting") )
				);
}
/* ========================================================================= */


/*  CLASS    =============================================================== */
//
//
//
//
/* ------------------------------------------------------------------------- */
/* ========================================================================= */


